﻿using Microsoft.Extensions.Logging;
using Rougamo.Context;
using System.Diagnostics;
using XC.Framework.Aop.Models;

namespace XC.Framework.Aop.Attributes
{
    /// <summary>
    /// 服务提供者
    /// </summary>
    public interface IAopServiceProvider
    {
        /// <summary>
        /// 服务提供者
        /// </summary>
        IServiceProvider ServiceProvider { get; set; }
    }

    /// <summary>
    /// 耗时统计
    /// </summary>
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
    public class TimeAttribute : AopMoAttribute
    {
        /// <summary>
        /// 定义事件拦截器
        /// </summary>
        public static List<Action<TimeContext, string>> TimeEvents { get; } = new List<Action<TimeContext, string>>();

        /// <summary>
        /// 备注/描述
        /// </summary>
        public string Remark { get; set; }

        /// <summary>
        /// 耗时统计
        /// </summary>
        /// <param name="remark">备注/描述</param>
        public TimeAttribute(string remark)
        {
            Remark = remark;
        }

        /// <summary>
        /// 方法执行前
        /// </summary>
        /// <param name="context"></param>
        public override void OnEntry(MethodContext context)
        {
            base.OnEntry(context);

            var stopwatch = new Stopwatch();
            //记录 api 执行耗时
            stopwatch.Restart();
            // 传递统计耗时对象
            context.Datas["Stopwatch"] = stopwatch;
            // 开始时间
            context.Datas["StartTime"] = DateTime.Now;
        }

        /// <summary>
        /// 方法执行异常
        /// </summary>
        /// <param name="context"></param>
        public override void OnException(MethodContext context)
        {

        }

        /// <summary>
        /// 方法执行成功后
        /// </summary>
        /// <param name="context"></param>
        public override void OnSuccess(MethodContext context)
        {

        }

        /// <summary>
        /// 获取日志文本
        /// </summary>
        /// <param name="context"></param>
        /// <param name="timeContext"></param>
        /// <returns></returns>
        protected virtual string GetLogText(MethodContext context, TimeContext timeContext)
        {
            var log = @$"
== 开始~结束时间：{timeContext.StartTime:yyyy-MM-dd HH:mm:ss.fff} ~ {timeContext.EndTime:yyyy-MM-dd HH:mm:ss.fff}
== 描述：        {Remark}
== 命名空间：     {timeContext.NameSpace} 
== 类名：        {timeContext.ClassName}
== 方法：        {timeContext.ReturnTypeName} {timeContext.MethodName}({(timeContext.ParameterStr is not null ? string.Join(",", timeContext.ParameterStr) : "")}) {{ ... }}
== 入参：        {(timeContext.ParameterValue is not null ? string.Join(",", timeContext.ParameterValue) : "")}
== 返回值：      {timeContext.ReturnValue}
== 耗时：        {timeContext.ElapsedMilliseconds} 毫秒! = {timeContext.ElapsedMilliseconds / 1000} 秒!
";

            return log;
        }

        /// <summary>
        /// 方法退出时，不论方法执行成功还是异常，都会执行
        /// </summary>
        /// <param name="context"></param>
        public override void OnExit(MethodContext context)
        {
            // 获取参数
            var stopwatch = context.Datas["Stopwatch"] as Stopwatch;

            if (stopwatch != null)
            {
                stopwatch.Stop();
                var endTime = DateTime.Now;

                // 获取日志对象
                var logger = GetLogger<TimeAttribute>(context);

                if (logger != null)
                {
                    // 对象
                    var timeContext = TimeContext.Map(context, Remark, stopwatch, endTime);

                    var log = @$"
=========================方法执行 [耗时统计] 开始=========================
==
";

                    log += GetLogText(context, timeContext);

                    log += @$"
==
=========================方法执行 [耗时统计] 结束=========================
";

                    logger.LogWarning(log);

                    // 调用事件
                    foreach (var item in TimeEvents)
                    {
                        item.Invoke(timeContext, log);
                    }
                }
            }

        }
    }
}
